package com.harvest.scientific.ladder.base

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.harvest.scientific.ladder.util.LogUtils
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.io.Serializable

open class BaModel : Serializable

interface IUiIntent

interface IUiState
abstract class BaseMVIViewModel<UiIntent : IUiIntent, UiState : IUiState> : ViewModel() {

    private val _uiStateFlow = MutableSharedFlow<UiState>()
    val uiStateFlow: SharedFlow<UiState> = _uiStateFlow.asSharedFlow()

    //页面事件的 Channel 分发
    private val _uiIntentFlow = Channel<UiIntent>(Channel.UNLIMITED)

    //更新页面状态
    fun updateUiState(reducer: () -> UiState) {
        viewModelScope.launch {
            _uiStateFlow.emit(reducer())
        }
//        _uiStateFlow.update { reducer(_uiStateFlow.value) }
    }

    //更新State
    fun <T> sendUiState(reducer: T.() -> T) {

    }

    //发送页面事件
    fun sendUiIntent(uiIntent: UiIntent) {
        viewModelScope.launch {
            LogUtils.d("sendUiIntent $uiIntent")
            _uiIntentFlow.send(uiIntent)
        }
    }

    init {
        // 这里是通过Channel的方式自动分发的。
        viewModelScope.launch {
            //收集意图 （观察者模式改变之后就自动更新）用于协程通信的，所以需要在协程中调用
            _uiIntentFlow.consumeAsFlow().collect { intent ->
                LogUtils.d("receive handleIntent")
                handleIntent(intent)
            }
        }.apply {
            invokeOnCompletion {
                LogUtils.d("baModel : invokeOnCompletion:")
            }
        }

    }

    //每个页面的 UiState 都不相同，必须实自己去创建
    protected abstract fun initUiState(): UiState

    //每个页面处理的 UiIntent 都不同，必须实现自己页面对应的状态处理
    protected abstract fun handleIntent(intent: UiIntent)

}
